//
//  CSDbManager.m
//  CSObjectSDK
//
//  Created by 瞿衡 on 16/6/29.
//  Copyright © 2016年 ND. All rights reserved.
//

#import "BZDataBase.h"
#import <BZPreHeaderComponent/BZPreHeaderComponent.h>
#import "BZBaseTableModel.h"
#import <objc/runtime.h>

typedef NS_ENUM(NSUInteger, ZZFPropertyType) {
    
    ZZFPropertyNSString       = 0,
    ZZFPropertyNSNumber       = 1,
    ZZFPropertyNSUInterger    = 2,
    ZZFPropertyLongLong       = 3,
    ZZFPropertyNSArray        = 4,
    ZZFPropertyNSMutableArray = 5,
    ZZFPropertyBool           = 6
};

#define ZZFTableVersion 1.0

@interface BZDataBase()

@property (nonatomic, strong)FMDatabaseQueue      *dbQueue;

@property (nonatomic, copy  ) NSString            *dbPath;

@property (nonatomic, strong) NSMutableDictionary *dbQueueDict;

@property (nonatomic, strong) NSMutableDictionary *dbPathDict;

@end

@implementation BZDataBase


static BZDataBase  * dbManage = nil;

+ (instancetype)shareDataBase{
    
    static dispatch_once_t onceToken ;
    
    dispatch_once(&onceToken, ^{
        dbManage = [[super allocWithZone:NULL] init] ;
    }) ;
    
    return dbManage;
}


+ (instancetype)allocWithZone:(struct _NSZone *)zone{
    
    return   [BZDataBase shareDataBase];
    
}

+ (id)copyWithZone:(struct _NSZone *)zone{
    
    return  [BZDataBase shareDataBase];
    
}

- (NSMutableDictionary *)dbPathDict{

    if (!_dbPathDict) {
        
        _dbPathDict = [[NSMutableDictionary alloc]init];
    }
    return _dbPathDict;
}



- (instancetype)init{
    
    self = [super init];

    if (self) {
        [self createTotalDbTable];
    }
    
    return  self;
}



- (void)createTotalDbTable{

    
    NSString *dirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)firstObject];
    
    NSString *dbPath  = [NSString stringWithFormat:@"%@/%@.db",dirPath,@"allTables"];
    
    BZLog(@"dbPath = %@",dbPath);
    NSString *allTable      = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS 'allTable' (tableName  TEXT,createTime LONG LONG,version LONG PRIMARY KEY)"];
    
    NSArray *tables = @[allTable];
    
    FMDatabaseQueue *dbQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];

    
    [dbQueue inDatabase:^(FMDatabase *db) {
        
        [db beginTransaction];
        BOOL isRollBack  = NO;
        BOOL success     = NO;
        @try {
            for (NSString *table in tables) {
                if (![db tableExists:table]) {
                    success = [db executeUpdate:table];
                    if (!success) {
                        BZLog(@"创建%@表失败",table);
                    }else{
                        BZLog(@"创建%@表成功",table);
                    }
                }
            }
        } @catch (NSException *exception) {
            isRollBack = YES;
            [db rollback];
        } @finally {
            [db commit];
        }
    }];
    
    self.dbQueue = dbQueue;

}


- (NSMutableDictionary *)dbQueueDict{

    if (!_dbQueueDict) {
        _dbQueueDict = [[NSMutableDictionary alloc]init];
    }
    return _dbQueueDict;
}


- (FMDatabaseQueue *)initialDbByName:(NSString *)dbName
                          tableNames:(NSArray <NSString *>*)tableNames
                       tableVersions:(NSArray *)tableVersions
                         tableModels:(NSArray *)tableModels
                            outError:(NSError *__autoreleasing *)outError{

    NSString *dirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)firstObject];
    NSString *dbPath  = [NSString stringWithFormat:@"%@/%@.db",dirPath,dbName];
    NSUInteger count  = tableNames.count ;
    NSMutableArray *tableSqlArr = [[NSMutableArray alloc]initWithCapacity:count];
    FMDatabaseQueue *dbQueue = [FMDatabaseQueue databaseQueueWithPath:dbPath];
    
//    NSFileManager *fileManager = [NSFileManager defaultManager];
    
//    if (![fileManager fileExistsAtPath:dbPath]) {
    
        for (NSUInteger i = 0; i < count; i++) {
            
            NSString *tableName = tableNames[i];
            id tableModel = tableModels[i];
            unsigned int count = 0;
            Ivar *members      =  class_copyIvarList([tableModel class],&count);
            NSString *tableSql = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS '%@' (",tableName];
            
            //遍历属性列表
            for (int i = 0 ; i < count; i++) {
                Ivar var = members[i];
                //获取变量名称
                const char *memberName = ivar_getName(var);
                //获取变量类型
                const char *memberType = ivar_getTypeEncoding(var);
                
                NSString *typeStr = [NSString stringWithCString:memberType encoding:NSUTF8StringEncoding];
                NSString *nameStr = [NSString stringWithCString:memberName encoding:NSUTF8StringEncoding];
                
                NSCharacterSet *charactset = [NSCharacterSet characterSetWithCharactersInString:@"_"];
               nameStr = [nameStr stringByTrimmingCharactersInSet:charactset];
                
                NSString *type = nil;
                    if ([typeStr isEqualToString:@"q"]) {//long long型
                        type = @"LONG LONG";
                    }else if ([typeStr isEqualToString:@"@\"NSString\""]){//字符型
                        type = @"TEXT";
                    }else if ([typeStr isEqualToString:@"B"]){//布尔型
                        type = @"BOOL";
                    }else if ([typeStr isEqualToString:@"i"] || [typeStr isEqualToString:@"Q"]){//数值型
                        type = @"INTEGER";
                    }else{
                        if (outError) {
                            *outError = [NSError errorWithDomain:@"ym.bz.zzf" code:-666 userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"%@-%@",@"数据库不支持该字段类型",typeStr]}];
                        }
                        break;
                    }
                tableSql = [NSString stringWithFormat:@"%@%@ %@",tableSql,nameStr,type];
                if (i != count - 1) {
                    tableSql = [NSString stringWithFormat:@"%@%@",tableSql,@","];
                }else{
                    tableSql = [NSString stringWithFormat:@"%@%@",tableSql,@")"];
                }
            }

            [tableSqlArr addObject:tableSql];
        }
    
    if (outError) {
        if (*outError) {
            return nil;
        }
    }
    [self.dbQueueDict setObject:dbQueue forKey:dbName];
    [self.dbPathDict setObject:dbPath forKey:dbName];

       __block BOOL success     = NO;
        [dbQueue inDatabase:^(FMDatabase *db) {
            
            [db beginTransaction];
            BOOL isRollBack  = NO;
            
            @try {
                for (NSString *table in tableSqlArr) {
                    if (![db tableExists:table]) {
                        success = [db executeUpdate:table];
                        if (!success) {
                            BZLog(@"创建%@表失败",table);
                        }else{
                            BZLog(@"创建%@表成功",table);
                        }
                    }
                }
            } @catch (NSException *exception) {
                isRollBack = YES;
                [db rollback];
            } @finally {
                [db commit];
            }
        }];
    
        NSTimeInterval time = [[NSDate date] timeIntervalSince1970];

        [self.dbQueue inDatabase:^(FMDatabase * _Nonnull db) {
            
            [db beginTransaction];
            BOOL isRollBack  = NO;
            
            @try {
                for (NSUInteger i = 0; i < count; i++) {
                    
                    NSNumber *versionN = tableVersions[i];
                    
                    [db executeUpdate:@"INSERT OR REPLACE INTO allTable (tableName,createTime,version) VALUES (?,?,?)",tableNames[i],@(time),versionN];
                }
                
            } @catch (NSException *exception) {
                isRollBack = YES;
                [db rollback];

            } @finally {
                [db commit];
            }
        }];
    

    
    return dbQueue;
}


- (FMDatabaseQueue *)getDbQueueWithDbName:(NSString *)dbName{

    
    
   return [self.dbQueueDict objectForKey:dbName];
    
}


- (NSString *)getDbPathWithDbName:(NSString *)dbName{

    return [self.dbPathDict objectForKey:dbName];

}



@end
